package com.vanrui.pcp.autocode.utils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.vanrui.pcp.autocode.constants.Constant;
import com.vanrui.pcp.autocode.model.entry.AutoCodeXml;
import com.vanrui.pcp.autocode.model.entry.Config;
import com.vanrui.pcp.autocode.model.entry.Jdbc;
import com.vanrui.pcp.autocode.model.entry.JdbcConfig;
import com.vanrui.pcp.autocode.model.entry.Macro;
import com.vanrui.pcp.autocode.model.entry.Package;
import com.vanrui.pcp.autocode.model.entry.Table;
import com.vanrui.pcp.autocode.model.entry.Template;
import com.vanrui.pcp.autocode.model.entry.TemplateDir;
import com.vanrui.pcp.autocode.model.entry.TypeMapping;

import freemarker.template.Configuration;
import freemarker.template.TemplateModel;
import freemarker.template.Version;

public class AutoCodeReader {
	
	private final static Logger logger = Logger.getLogger(AutoCodeReader.class);
	
	private Config config;
	private AutoCodeXml autoCodeXml;
	
	public AutoCodeReader(Config config){
		this.config = config;
	}
	
	public void LoadConfig(){
		logger.debug("load config autoCode.xml ...");
		//String path = System.getProperty("user.dir")+"/src/autoCode.xml";
		try {
			JAXBContext context = JAXBContext.newInstance(AutoCodeXml.class);  
			Unmarshaller unmarshaller = context.createUnmarshaller();  
			autoCodeXml = (AutoCodeXml) unmarshaller.unmarshal(getClass().getResourceAsStream("/autoCode.xml"));
			dealXML();
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			new Exception("解析autoCode.xml出错 ...", e);
		}
	}
	
	public static void main(String[] args) throws Exception {
		//new AutoCodeReader().LoadConfig();
	}
	
	private void dealXML() throws Exception{
		getVersion(autoCodeXml.getVersion());
		
		readTypeMappings(autoCodeXml.getTypeMappings());
		
		readMacros(autoCodeXml.getMacros());
		
		readTemplateDir(autoCodeXml.getTemplateDir());
		
		readTemplates(autoCodeXml.getPackages(), autoCodeXml.getProjectPath());
		
		readJDBC(autoCodeXml.getJdbc());
		
		readTableName(autoCodeXml.getTables());
	}
	
	private void readTableName(List<Table> list) throws Exception {
		if(list == null){
			throw new Exception("加载配置出错：缺少配置表名称");
		}
		config.setTables(list);
	}

	private void readJDBC(Jdbc jdbc) throws Exception {
		if(jdbc == null){
			throw new Exception("加载数据库连接失败，缺少连接配置");
		}
		if(StringUtils.isAnyBlank(jdbc.getUrl(), jdbc.getUser(), jdbc.getPassword(), jdbc.getDriver())){
			throw new Exception("加载数据库连接失败，请检查用户名、密码、链接、驱动是否有配置");
		}
		JdbcConfig jdbcConfig = new JdbcConfig();
		jdbcConfig.setUrl(jdbc.getUrl());
		jdbcConfig.setUser(jdbc.getUser());
		jdbcConfig.setPassword(jdbc.getPassword());
		jdbcConfig.setDriver(jdbc.getDriver());
		config.setJdbcConfig(jdbcConfig);
	}

	private void readTemplateDir(TemplateDir templateDir){
		config.setTemplateDir(templateDir.getPath());
	}
	
	private void readTemplates(List<Package> list, String projectPath) throws Exception {
		Map<String, Template> templates = new HashMap<String, Template>();
		config.setProjectPath(projectPath);
		
		if(StringUtils.isBlank(config.getProjectPath())){
			throw new Exception("加载模板文件出错：缺少配置工程目录"+Constant.PROJECT_PATH);
		}
		
		for (Package pkg : list) {
			if(StringUtils.isBlank(pkg.getTemplate()) || StringUtils.isBlank(pkg.getPkg()) 
					|| !pkg.isEnable()){
    			continue;
    		}
			Template tmpe = new Template();
    		tmpe.setTemplate(pkg.getTemplate());
    		tmpe.setPckgName(pkg.getPkg().replaceAll("\\s", ""));
    		tmpe.setFileType(pkg.getFileType());
    		tmpe.setShareable(pkg.isShareable());
    		String prefix = StringUtils.isBlank(pkg.getPrefix()) ? "":pkg.getPrefix();
    		String suffix = StringUtils.isBlank(pkg.getSuffix()) ? "":pkg.getSuffix();
    		tmpe.setPrefix(prefix);
    		tmpe.setSuffix(suffix);
    		templates.put(pkg.getTemplate(), tmpe);
		}
		if(templates.size() == 0){
			throw new Exception("加载模板文件出错：没有可用的模板文件");
		}
		config.setTemplates(templates);
	}


	private void getVersion(String ver) throws Exception{
		Version version = null;
		if(StringUtils.isBlank(ver)){
			version  = Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS;
		}else if(StringUtils.equals(Constant.VERSION_2_3_0, ver)){
			version = Configuration.VERSION_2_3_0;                    
		}else if(StringUtils.equals(Constant.VERSION_2_3_19, ver)){
			version = Configuration.VERSION_2_3_19;                   
		}else if(StringUtils.equals(Constant.VERSION_2_3_20, ver)){
			version = Configuration.VERSION_2_3_20;                   
		}else if(StringUtils.equals(Constant.VERSION_2_3_21, ver)){
			version = Configuration.VERSION_2_3_21;                   
		}else if(StringUtils.equals(Constant.VERSION_2_3_22, ver)){
			version = Configuration.VERSION_2_3_22;                   
		}else if(StringUtils.equals(Constant.VERSION_2_3_23, ver)){
			version = Configuration.VERSION_2_3_23;                   
		}
		if(version == null){
			throw new Exception("不支持的版本，version:"+ver);
		}
		config.setVersion(version);
	}
	
	private void readTypeMappings(List<TypeMapping> list){ 
		
		Map<String, String> types = new HashMap<String, String>();
		for (TypeMapping mapping : list) {
			types.put(mapping.getColumnType(), mapping.getFieldType());
		}
		if(types.size() == 0){
			types.put(Constant.ASTERISK, Constant.STRING);
		}
		config.setTypes(types);
	}
	
	private void readMacros(List<Macro> list) throws Exception{
		Map<String, TemplateModel> variables = new HashMap<String, TemplateModel>();
		for (Macro macro : list) {
    		TemplateModel obj =(TemplateModel)BeanUtil.getClassInstance(macro.getTemplateModel().trim());
			variables.put(macro.getName(), obj);
    	}
    	config.setVariables(variables);
	}

}
